﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;

using Microsoft.Rtc.Collaboration;
using Microsoft.Rtc.Collaboration.Samples.HTMLPresenceControls.Service.Common;
using Microsoft.Rtc.Collaboration.Presence;
using Microsoft.Rtc.Signaling;

namespace Microsoft.Rtc.Collaboration.Samples.HTMLPresenceControls.Service
{
    /// <summary>
    /// The default UCMA implementation of IPresenceProvider.
    /// Creates a collaboration platfrom and endpoint and then subscribes to the presence updates of the requested contacts
    /// </summary>
    public class UcPresenceProvider : Microsoft.Rtc.Collaboration.Samples.HTMLPresenceControls.Service.IPresenceProvider
    {
        private ApplicationEndpoint m_applicationEndpoint;
        private RemotePresenceView m_remotePresenceView;

        public event EventHandler<PresenceChangedEventArgs> PresenceChanged;

        public UcPresenceProvider(ApplicationEndpoint endpoint)
        {
            m_applicationEndpoint = endpoint;
        }

        public bool Start()
        {
            return InitializeRemotePresenceView();
        }

        public void SubscribeToPresence(string sipUri)
        {
            if (!IsAlreadySubscribed(sipUri))
            {
                Subscribe(sipUri);
            }
        }

        public void UnsubscribeToPresence(string sipUri)
        {
            if (IsAlreadySubscribed(sipUri))
            {
                Unsubscribe(sipUri);
            }
        }

        private bool IsAlreadySubscribed(string sipUri)
        {
            if (m_remotePresenceView != null)
            {
                var subscriptions = m_remotePresenceView.GetPresentities();
                return subscriptions.Any(s => s.Equals(sipUri, StringComparison.InvariantCultureIgnoreCase));
            }
            else return false;
        }

        private void Subscribe(string sipUri)
        {
            SipUriParser uriParser;
            if (SipUriParser.TryParse(sipUri, out uriParser))
            {
                var subscriptionTargets = new List<RemotePresentitySubscriptionTarget>();
                subscriptionTargets.Add(new RemotePresentitySubscriptionTarget(uriParser.ToString()));
                // Immediately fires NotificationReceived with current presence of targets
                m_remotePresenceView.StartSubscribingToPresentities(subscriptionTargets);
            }
        }

        private void Unsubscribe(string sipUri)
        {
            SipUriParser uriParser;
            if (SipUriParser.TryParse(sipUri, out uriParser))
            {
                m_remotePresenceView.StartUnsubscribingToPresentities(new List<string> { sipUri });
            }
        }

        private void RemotePresenceView_PresenceNotificationReceived(object sender, RemotePresentitiesNotificationEventArgs e)
        {
            List<PresenceSubscription> presences = new List<PresenceSubscription>();
            foreach (var notification in e.Notifications)
            {
                presences.Add(ConvertNotificationToPresence(notification));
            }
            if (PresenceChanged != null)
            {
                PresenceChanged(this, new PresenceChangedEventArgs { Presences = presences });
            }
        }

        private PresenceSubscription ConvertNotificationToPresence(RemotePresentityNotification notification)
        {
            //after the first notification for a contact, you only get the categories that changed next time
            //so after the first notification if presence changes, you only get presence; if name changes you only get contact card
            long availability = PresenceSubscription.NoChangeInAvailability;
            string status = PresenceSubscription.NoChange;
            string contactName = PresenceSubscription.NoChange;

            var presence = notification.AggregatedPresenceState;
            if (presence != null)
            {
                availability = presence.AvailabilityValue;
                status = AvailabilityToStatusConverter.Convert(availability);
            }

            var contactCard = notification.ContactCard;
            if (contactCard != null)
            {
                contactName = contactCard.DisplayName;
            }

            return new PresenceSubscription
            {
                Availability = availability,
                ContactName = contactName,
                SipUri = notification.PresentityUri,
                Status = status
            };
        }

        private bool InitializeRemotePresenceView()
        {
            try
            {
                // RemotePresenceView provides a unified way to request presence for a set of presentities
                m_remotePresenceView = new RemotePresenceView(
                    m_applicationEndpoint,
                    new RemotePresenceViewSettings() { SubscriptionMode = RemotePresenceViewSubscriptionMode.Default });


                // Wire up NotificationReceived before adding targets
                m_remotePresenceView.PresenceNotificationReceived +=
                    new EventHandler<RemotePresentitiesNotificationEventArgs>(RemotePresenceView_PresenceNotificationReceived);
                Helper.Logger.Info("UcPresenceProvider started");
                return true;
            }
            catch (Exception ex)
            {
                Helper.Logger.Error("UCPresenceProvider failed: Could not initialize remote presence view {0}", ex);
                return false;
            }
        }
    }
}
